package khs.java_crypt.main.java;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.spec.AlgorithmParameterSpec;
import java.util.Arrays;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;

import java.util.Arrays;

/**
 * Hello world!
 *
 */
public class App 
{
    private static BufferedReader bufferedReader;
    private static final String AESKEY = "abcdefghijklmnopqrstuvwxyz123456"; // 32bite
    private static final String SEEDKEY = "abcdefghijklmnop"; // 16bite
    private static final String TRIPLEDESKEY = "abcdefghijklmnopqrstuvwx"; // 24bite
    
    public static void main( String[] args ) throws IOException, NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException
    {
        bufferedReader = new BufferedReader(new InputStreamReader(System.in));
        String input_mode;
        
        do{
            fnPrintMode();
            input_mode = bufferedReader.readLine();
            
            switch(input_mode){
            case "1":
                fnSha256Mode();
                break;
            case "2":
                fnAes256Mode();
                break;
            case "3":
                fnSeed128CbcMode();
                break;
            case "4":
                fn3DesMode();
                break;
            }
        }while(!input_mode.equals("q"));
        
        bufferedReader.close();
    }
    
    public static void fnPrintMode(){
        System.out.println("1. sha256");
        System.out.println("2. aes256cbc");
        System.out.println("3. seed128cbc");
        System.out.println("4. 3des");
        System.out.println("q. quit");
    }
    
    public static void fn3DesMode() throws IOException, InvalidKeyException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException
    {
        System.out.print("input text: ");
        String input_text = bufferedReader.readLine();
        
        byte[] iv = new byte[Cipher.getInstance("TripleDES/CBC/PKCS5Padding").getBlockSize()];
        Arrays.fill(iv, (byte)0);
        
        byte[] encrypt = fn3DesEncrypt(input_text.getBytes(), TRIPLEDESKEY.getBytes(), iv);
        byte[] decrypt = fn3DesDecrypt(encrypt, TRIPLEDESKEY.getBytes(), iv);
        
        System.out.println(Base64.encodeBase64String(encrypt));
        System.out.println(new String(decrypt));
    }
    
    public static byte[] fn3DesEncrypt(byte[] decrypt, byte[] key, byte[] iv) throws InvalidKeyException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException
    {
        byte[] rtn;
        
        SecretKey secretKey = new SecretKeySpec(key, "TripleDES");
        Cipher cipher = Cipher.getInstance("TripleDES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv));
        
        rtn = cipher.doFinal(decrypt);
        
        return rtn;
    }
    
    public static byte[] fn3DesDecrypt(byte[] encrypt, byte[] key, byte[] iv) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException
    {
        byte[] rtn;
        
        SecretKey secretKey = new SecretKeySpec(key, "TripleDES");
        Cipher cipher = Cipher.getInstance("TripleDES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv));
        
        rtn = cipher.doFinal(encrypt);
        
        return rtn;
    }
    
    public static void fnSha256Mode() throws IOException, NoSuchAlgorithmException
    {
        System.out.print("input text: ");
        String input_text = bufferedReader.readLine();
        
        byte[] encodeByteArray = fnSha256Encrypt(input_text.getBytes());
        //System.out.println(Hex.encodeHexString(encodeByteArray));
        System.out.println(Base64.encodeBase64String(encodeByteArray));
    }
    
    public static byte[] fnSha256Encrypt(byte[] decode) throws NoSuchAlgorithmException
    {
        byte[] rtn;
        
        MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
        messageDigest.update(decode);
        rtn = messageDigest.digest();
        
        return rtn;
    }
    
    public static void fnAes256Mode() throws IOException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException
    {
        System.out.print("input text: ");
        String input_text = bufferedReader.readLine();
        
        byte[] iv = new byte[Cipher.getInstance("AES/CBC/PKCS5Padding").getBlockSize()];
        Arrays.fill(iv, (byte)0);
        
        byte[] encrypt = fnAes256Encrypt(input_text.getBytes(), AESKEY.getBytes(), iv);
        byte[] decrypt = fnAes256Decrypt(encrypt, AESKEY.getBytes(), iv);
        
        System.out.println(Base64.encodeBase64String(encrypt));
        System.out.println(new String(decrypt));
    }
    
    public static byte[] fnAes256Encrypt(byte[] decrypt, byte[] key, byte[] iv) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException
    {
        byte[] rtn;
        
        SecretKey secretKey = new SecretKeySpec(key, "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv));
        
        rtn = cipher.doFinal(decrypt);
        
        return rtn;
    }
    
    public static byte[] fnAes256Decrypt(byte[] encrypt, byte[] key, byte[] iv) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException
    {
        byte[] rtn;
        
        SecretKey secretKey = new SecretKeySpec(key, "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv));
        
        rtn = cipher.doFinal(encrypt);
        
        return rtn;
    }
    
    public static void fnSeed128CbcMode() throws IOException
    {
        System.out.print("input text: ");
        String input_text = bufferedReader.readLine();
        
        byte[] iv = new byte[KISA_SEED_CBC.getBlockSizeSeed()];
        Arrays.fill(iv, (byte)0);
        
        byte[] encrypt = fnSeed128CbcEncrypt(input_text.getBytes(), SEEDKEY.getBytes(), iv);
        System.out.println(Base64.encodeBase64String(encrypt));
        
        byte[] decrypt = fnSeed128CbcDecrypt(encrypt, SEEDKEY.getBytes(), iv);
        System.out.println(new String(decrypt));
    }
    
    public static byte[] fnSeed128CbcEncrypt(byte[] decrypt, byte[] key, byte[] iv)
    {
        byte[] rtn;
        
        rtn = KISA_SEED_CBC.SEED_CBC_Encrypt(key, iv, decrypt, 0, decrypt.length);
        
        return rtn;
    }
    
    public static byte[] fnSeed128CbcDecrypt(byte[] encrypt, byte[] key, byte[] iv)
    {
        byte[] rtn;
        
        rtn = KISA_SEED_CBC.SEED_CBC_Decrypt(key, iv, encrypt, 0, encrypt.length);
        
        return rtn;
    }
}
